package mumu.android.lib.tool;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

import mumu.android.R;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.widget.ImageView;

public class ImageLoader {
	private String TAG="SYNC_IMAGE";
	private Context mContext;
	private static ImageLoader instance;
	// 是否需要重本地文件中获取
	private Boolean needfromFile = true;
	// private Boolean needMemeryCache = true;
	private Boolean fromMemeryCacheFirst = true;
	// 队列最高数量
	private int MaxCount = 50;

	class ImgTask {
		String url;
		ImageView imageView;
		/**
		 * 失败图片
		 */
		Integer fail_img;
		/**
		 * 动画
		 */
		Integer anim_src;
	}

	private ExecutorService executorService; // 线程池
	private ImageMemoryCache memoryCache; // 内存缓存
	private ImageFileCache fileCache; // 文件缓存
	/**
	 * 因为ListView或GridView的原理是用上面移出屏幕的item去填充下面新显示的item,
	 * 这里的img是item里的内容，所以这里的taskMap保存的始终是当前屏幕内的所有ImageView。
	 */
	private Map<String, ImageView> taskMap; // 存放任务
	private final LinkedBlockingQueue<ImgTask> trackerQueue = new LinkedBlockingQueue<ImgTask>();
	private boolean allowLoad = true; // 是否允许加载图片

	private ImageLoader(Context context) {
		// 获取当前系统的CPU数目
		int cpuNums = Runtime.getRuntime().availableProcessors();
		// 根据系统资源情况灵活定义线程池大小
		this.executorService = Executors.newFixedThreadPool(cpuNums + 1);
		this.memoryCache = new ImageMemoryCache(context);
		this.fileCache = new ImageFileCache();
		this.taskMap = new HashMap<String, ImageView>();
		this.mContext = context;
	}

	/**
	 * 使用单例，保证整个应用中只有一个线程池和一份内存缓存和文件缓存
	 */
	public static ImageLoader getInstance(Context context) {
		if (instance == null)
			instance = new ImageLoader(context);
		return instance;
	}

	public ImageLoader setNeedFromFile(Boolean needfromFile) {
		this.needfromFile = needfromFile;
		return this;
	}

	public ImageLoader setMaxLinked(int count) {
		this.MaxCount = count;
		return this;
	}

	public ImageLoader setFromCacheFirst(Boolean fromCacheFirst) {
		this.fromMemeryCacheFirst = fromCacheFirst;
		return this;
	}

	/**
	 * 恢复为初始可加载图片的状态
	 */
	public void restore() {
		this.allowLoad = true;
	}

	/**
	 * 锁住时不允许加载图片
	 */
	public void lock() {
		this.allowLoad = false;
	}

	/**
	 * 解锁时加载图片
	 */
	public void unlock() {
		this.allowLoad = true;
		doTask();
	}

	public ImageLoader addTask(String url, ImageView img) {
		return addTask(url, img, R.drawable.image_fail, 0);
	}

	public ImageLoader addTaskAnim(String url, ImageView img, Integer animSrc) {
		return addTask(url, img, R.drawable.image_fail, animSrc);
	}
	
	public ImageLoader addTask(String url, ImageView img, Integer imgfail) {
		return addTask(url, img, imgfail, 0);
	}

	/**
	 * 添加任务
	 */
	public ImageLoader addTask(String url, ImageView img, Integer imgfail, Integer animSrc) {
		// 判断是否为空
		if (img == null)
			return this; 

		img.setTag(url);
		ImgTask imgTask = new ImgTask();
		imgTask.imageView = img;
		imgTask.url = url;
		imgTask.fail_img = imgfail;
		imgTask.anim_src = animSrc;

		if (url == null || url.equals("")) {
			img.setImageBitmap(BitmapFactory.decodeResource(mContext.getResources(), imgTask.fail_img));
			return this;
		}
		if (fromMemeryCacheFirst) {
			// 先从内存缓存中获取，取到直接加载
			Bitmap bitmap = memoryCache.getBitmapFromCache(url);
			if (bitmap != null) {
				MLog.i(TAG, "addTask==>from memoryCache==>" + url);
				//if (imgTask.anim_src != null && imgTask.anim_src > 0)
					//AnimHp.imageAnim(imgTask.imageView.getContext(), bitmap, imgTask.imageView, imgTask.anim_src);
				//else
					img.setImageBitmap(bitmap);
				return this;
			} else {
				img.setImageBitmap(BitmapFactory.decodeResource(mContext.getResources(),imgTask.fail_img));
			}
		} else {
			img.setImageBitmap(BitmapFactory.decodeResource(mContext.getResources(), imgTask.fail_img));
		}

		synchronized (trackerQueue) {
			MLog.i(TAG, "addTask==>synchronized put task  ==>" + url);
			// 添加任务
			trackerQueue.add(imgTask);
			// 超出删除
			if (trackerQueue.size() > MaxCount) {
				for (int i = 0; i < trackerQueue.size() - MaxCount; i++) {
					try {
						trackerQueue.take();
						MLog.i(TAG, "delete task   ==task count" + trackerQueue.size());
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}

		return this;

		// /**
		// * 每次添加任务时，判断是否允许下载，允许则直接下载
		// */
		// if (allowLoad) {
		// doTask();
		// }
	}

	/**
	 * 加载存放任务中的所有图片
	 */
	public void doTask() {
		if (allowLoad) {
			synchronized (trackerQueue) {
				while (!trackerQueue.isEmpty()) {
					try {
						ImgTask imgTask = trackerQueue.take();
						if (imgTask != null && imgTask.imageView != null && imgTask.url != null && imgTask.imageView.getTag() != null) {

							/**
							 * 过滤是否图片地址已经更改
							 * 图片错位问题的本质源于我们的listview使用了缓存convertView，
							 * 假设一种场景，一个listview一屏显示九个item
							 * ，那么在拉出第十个item的时候，事实上该item是重复使用了第一个item，
							 * 也就是说在第一个item从网络中下载图片并最终要显示的时候其实该item已经不在当前显示区域内了，
							 * 此时显示的后果将是在可能在第十个item上输出图像
							 * ，这就导致了图片错位的问题。所以解决之道在于可见则显示，不可见则不显示。
							 * 在ImageLoader里有个imageViews的map对象
							 * ，就是用于保存当前显示区域图像对应的url集，在显示前判断处理一下即可。
							 */
							if (imgTask.imageView.getTag().equals(imgTask.url)) {
								loadImage(imgTask);
								MLog.i(TAG, "doTask==>dotask=" + (String) imgTask.imageView.getTag());
							} else {
								MLog.i(TAG, "doTask  continu================================>dotask=" + (String) imgTask.imageView.getTag());
							}
						} else {
							if (imgTask.imageView != null)
								imgTask.imageView.setImageResource(imgTask.fail_img);
						}
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}

	private void loadImage(ImgTask imgTask) {
		this.executorService.submit(new TaskWithResult(new TaskHandler(imgTask), imgTask));
	}

	/*** 获得一个图片,从三个地方获取,首先是内存缓存,然后是文件缓存,最后从网络获取 ***/
	private Bitmap getBitmap(ImgTask imgTask) {
		String url = imgTask.url;
		// 从内存缓存中获取图片
		Bitmap result = null;
		result = memoryCache.getBitmapFromCache(url);
		if (result == null) {
			// 文件缓存中获取
			if (needfromFile)
				result = fileCache.getImage(url);
			if (result == null) {
				// 从网络获取
				result = ImageGetFromHttp.downloadBitmap(url);
				if (result != null) {
					if (needfromFile)
						fileCache.saveBitmap(result, url);
					memoryCache.addBitmapToCache(url, result);
				}
			} else {
				// 添加到内存缓存
				memoryCache.addBitmapToCache(url, result);
			}
		}
		// 返回错误图片
		if (result == null)
			result = BitmapFactory.decodeResource(mContext.getResources(), imgTask.fail_img);
		return result;
	}

	/*** 子线程任务 ***/
	private class TaskWithResult implements Callable<String> {
		private ImgTask imgTask;
		private Handler handler;

		public TaskWithResult(Handler handler, ImgTask imgTask) {
			this.imgTask = imgTask;
			this.handler = handler;
		}

		@Override
		public String call() throws Exception {
			Message msg = new Message();
			msg.obj = getBitmap(imgTask);
			if (msg.obj != null) {
				handler.sendMessage(msg);
			}
			return imgTask.url;
		}
	}

	/*** 完成消息 ***/
	private class TaskHandler extends Handler {
		ImgTask imgTask;

		public TaskHandler(ImgTask imgTask) {
			this.imgTask = imgTask;
		}

		@Override
		public void handleMessage(Message msg) {
			/*** 查看ImageView需要显示的图片是否被改变 ***/
			if (imgTask.imageView.getTag().equals(imgTask.url)) {
				if (msg.obj != null) {
					Bitmap bitmap = (Bitmap) msg.obj;
					//if (imgTask.anim_src != null && imgTask.anim_src > 0)
					//	AnimHp.imageAnim(imgTask.imageView.getContext(), bitmap, imgTask.imageView, imgTask.anim_src);
					//else
						imgTask.imageView.setImageBitmap(bitmap);
				}
			}
		}
	}

}